package com.heima.account.action;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.heima.account.entity.Account;
import com.heima.account.entity.AccountFreeze;
import com.heima.account.service.IAccountFreezeService;
import com.heima.account.service.IAccountService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author: itheima
 * @create: 2022-04-29 15:30
 */
@Slf4j
@Service
public class AccountActionImpl implements AccountAction {

    @Autowired
    private IAccountService accountService;

    @Autowired
    private IAccountFreezeService freezeService;


    /**
     * TODO 避免业务悬挂:先执行Cancel 分之事务从阻塞中恢复后然后执行了 try方法
     * Try方法：1.扣减账户金额   2.新增冻结记录
     *
     * @param userId 业务参数 用户ID
     * @param money  业务参数 扣减金额
     */
    @Override
    public void deduct(Integer userId, Integer money) {
        log.error("Try方法被执行了");
        // 从Seata上下文中获取全局事务ID
        String xid = RootContext.getXID();

        //0.为了避免出现业务悬挂，根据全局事务ID查询动机记录 如果冻结记录存在 说明Cacel执行过了，则拒绝业务执行
        AccountFreeze freeze = freezeService.getById(xid);
        if (freeze != null) {
            //说明Cancel执行过了，拒绝执行业务
            return;
        }
        //1.扣减账户金额
        LambdaUpdateWrapper<Account> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Account::getUserId, userId);
        updateWrapper.setSql("money = money-" + money);
        accountService.update(updateWrapper);

        // 2.新增冻结记录
        AccountFreeze accountFreeze = new AccountFreeze();
        accountFreeze.setFreezeMoney(money);
        accountFreeze.setUserId(userId);
        accountFreeze.setXid(xid);
        freezeService.save(accountFreeze);
    }


    /**
     * 确认方法：根据全局事务ID删除冻结记录
     *
     * @param context Seata上下文环境
     * @return
     */
    @Override
    public boolean confirm(BusinessActionContext context) {
        log.error("执行确认方法，删除冻结记录");
        String xid = context.getXid();
        return freezeService.removeById(xid);
    }

    /**
     * TODO 没有允许空回滚
     * 补偿方法：反向补偿   1.修改账户余额    2.删除冻结表记录
     *
     * @param context
     * @return
     */
    @Override
    public boolean cancel(BusinessActionContext context) {
        log.error("执行补偿方法，释放冻结资源！");
        //1.1 根据全局事务ID查询冻结表记录，用于恢复账户余额
        String xid = context.getXid();

        //1.修改账户余额
        AccountFreeze freeze = freezeService.getById(xid);
        if (freeze != null) {
            //说明Try必然执行过了
            LambdaUpdateWrapper<Account> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Account::getUserId, freeze.getUserId());
            updateWrapper.setSql("money = money+" + freeze.getFreezeMoney());
            accountService.update(updateWrapper);

            // 2.删除冻结表记录
            return freezeService.removeById(xid);
        } else {
            return true;
        }
    }
}
